#pragma once

#include <vector>
#include "Thread.h"
#include "Mutex.h"
#include "Cond.h"
#include "Sem.h"

namespace zmh
{
    template <class T>
    class ring_queue
    {
    public:
        ring_queue(const int capacity)
            : _rq(capacity),
              _capacity(capacity),
              _empty_sem(capacity),
              _value_sem(0),
              _prod_step(0),
              _cons_step(0) {}

        void producer(const T &data) // 生产者
        {
            // 申请无数据信号量
            _empty_sem.P();
            // 申请生产者互斥锁
            auto_Mutex guard_mutex(_prod_mutex);
            // 生产数据
            _rq[_prod_step] = data; // data要么是左值引用，要么是右值引用(临时变量)
            // 更新生产者位置
            _prod_step = (_prod_step + 1) % _capacity;
            // 释放有数据信号量
            _value_sem.V();
        }
        T consumer()
        {
            // 申请有数据信号量
            _value_sem.P();
            // 申请消费者互斥锁
            auto_Mutex guard_mutex(_cons_mutex);
            // 消费数据
            auto &ret = _rq[_cons_step];
            // 更新消费者位置
            _cons_step = (_cons_step + 1) % _capacity;
            // 释放无数据信号量
            _empty_sem.V();
            // 返回结果
            return ret;
        }

    private:
        std::vector<T> _rq; // 所用容器
        int _capacity;      // 容量大小
        Sem _empty_sem;     // 无数据 for 信号量
        Sem _value_sem;     // 有数据 for 信号量
        int _prod_step;     // 生产者位置
        int _cons_step;     // 消费者位置
        Mutex _prod_mutex;  // 锁 for 生产者
        Mutex _cons_mutex;  // 锁 for 消费者
    };
}